#include "file.h"
#include "ui_file.h"
#include "client.h"
#include <QInputDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QTimer>

File::File(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::File)
{
    ui->setupUi(this);
    m_pShareFile = new ShareFile;
    m_strCurPath = QString("./filesys/%1").arg(Client::getInstance().m_strLoginName);//构造函数中初始化
    m_strUserPath = m_strCurPath;
    m_bUpload = false;
    m_bDownload = false;
    flushFile();//构造函数调用
}

File::~File()
{
    delete ui;
    delete m_pShareFile;
}

void File::flushFile()//刷新文件封装函数
{
    PDU* pdu = mkPDU(m_strCurPath.size()+1);//构建pdu
    pdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_FILE_REQUEST;//pdu类型
    memcpy(pdu->caMsg, m_strCurPath.toStdString().c_str(), m_strCurPath.size());//传当前路径给服务器
    Client::getInstance().sendPDU(pdu);//发送
    qDebug()<<"flushFile end";

    //半包测试
    //PDU* pdu = mkPDU(m_strCurPath.size()+1);
    //pdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_FILE_REQUEST;
    //memcpy(pdu->caMsg, m_strCurPath.toStdString().c_str(), m_strCurPath.size());
    //Client::getInstance().m_tcpSocket.write((char*)pdu, sizeof(PDU));
    //QTimer::singleShot(1000,[&] {//lamda表达式
    //    Client::getInstance().m_tcpSocket.write(m_strCurPath.toStdString().c_str(), m_strCurPath.size()+1);
    //});
    //free(pdu);
    //pdu = NULL;
}

void File::showFileList(QList<FileInfo *> pFileInfoList)//更新文件列表
{
    foreach(FileInfo* pFileInfo, m_pFileInfoList){// 清空原有的文件信息列表
        delete pFileInfo;
    }
    m_pFileInfoList.clear();
    m_pFileInfoList = pFileInfoList;// 更新文件信息列表
    ui->file_LW->clear();// 清空文件列表控件
    foreach(FileInfo* pFileInfo, pFileInfoList){// 遍历文件信息列表，创建列表项并添加到文件列表控件中
        QListWidgetItem* pItem = new QListWidgetItem;// 创建列表项
        // 根据文件类型设置图标
        if(pFileInfo->FileType == 0){
            pItem->setIcon(QIcon(QPixmap(":./dir.png")));// 目录
        }
        else if(pFileInfo->FileType == 1){
            pItem->setIcon(QIcon(QPixmap(":./file.png")));// 文件
        }
        pItem->setText(pFileInfo->caName);// 设置列表项文本为文件名
        ui->file_LW->addItem(pItem);// 添加列表项到文件列表控件中
    }
}

void File::uploadFile()//上传文件数据
{
    //打开文件
    QFile file(m_strUploadFilePath);
    if(!file.open(QIODevice::ReadOnly)){
        QMessageBox::warning(this,"上传文件","打开文件失败");
        return;
    }
    //更新上传状态
    m_bUpload = true;
    //构建pdu
    PDU* datapdu = mkPDU(4096);
    datapdu->uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_DATA_REQUEST;
    //循环读取文件并发送给服务器
    qint64 ret;
    while(true){
        ret = file.read(datapdu->caMsg,4096);
        if(ret == 0){
            break;
        }
        if(ret < 0){
            QMessageBox::warning(this,"上传文件","上传文件失败：读取文件失败");
            break;
        }
        //当最后一次读取时，ret可能不是4096，需要更新pdu长度
        datapdu->uiMsgLen = ret;
        datapdu->uiPDULen = sizeof(PDU)+ret;
        //不能直接调用sendpdu函数，因为这里边会释放掉datapdu,但是这是循环调用。
        Client::getInstance().m_tcpSocket.write((char*)datapdu, datapdu->uiPDULen);
    }
    //更新上传状态，关闭文件释放pdu
    m_bUpload = false;
    file.close();
    free(datapdu);
    datapdu = NULL;
}

void File::downloadFile(qint64 iFileSize)//File定义一个下载文件的函数
{
    qDebug() <<"downloadFile start";
    //更新下载文件相关的属性
    m_iDownloadTotal = iFileSize;
    m_iDownloadReceived = 0;
    //创建并打开保存下载路径下的文件
    m_fDownloadFile.setFileName(m_strSavePath);
    if(!m_fDownloadFile.open(QIODevice::WriteOnly)){
        QMessageBox::warning(this,"下载文件","打开文件失败");
        return;
    }
    //发送服务器，开始下载
    PDU* pdu = mkPDU(0);
    pdu->uiMsgType = ENUM_MSG_TYPE_DOWNLOAD_FILE_DATA_REQUEST;
    Client::getInstance().sendPDU(pdu);
    qDebug() <<"downloadFile end";
}

void File::downloadFileData(char *buffer, int size)//File定义一个下载文件数据的函数
{
    qDebug() <<"downloadFileData start";
    m_fDownloadFile.write(buffer,size);
    m_iDownloadReceived += size;
    if(m_iDownloadReceived < m_iDownloadTotal){
        return;
    }
    m_fDownloadFile.close();
    m_bDownload = false;
    QMessageBox::information(this, "下载文件", "下载文件完成");
}

void File::on_mkDir_PB_clicked()//创建文件夹槽函数
{
    QString strNewDir = QInputDialog::getText(this, "新建文件夹", "新建文件夹名");//创建输入框
    if(strNewDir.isEmpty() || strNewDir.size() > 32){// 判断文件夹名是否为空或长度是否非法
        QMessageBox::warning(this, "新建文件夹", "文件夹名长度非法");
        return;
    }
    PDU* pdu = mkPDU(m_strCurPath.size()+1);// 构建请求PDU
    pdu->uiMsgType = ENUM_MSG_TYPE_MKDIR_REQUEST;// 设置请求PDU类型为创建文件夹请求
    memcpy(pdu->caData,strNewDir.toStdString().c_str(),32);// 将新建文件夹名称拷贝到请求PDU的数据域中
    memcpy(pdu->caMsg,m_strCurPath.toStdString().c_str(),m_strCurPath.size());// 将当前路径拷贝到请求PDU的消息域中
    Client::getInstance().sendPDU(pdu);// 发送请求PDU
}

void File::on_flushFile_PB_clicked()
{
    flushFile();
}

void File::on_delDir_PB_clicked()//删除文件夹槽函数
{
    //用户是否选择了文件夹
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    if(pItem == NULL){
        QMessageBox::warning(this,"删除文件夹","请选择要删除的文件夹");
        return;
    }
    //确认用户选择的文件类型是否为文件夹
    QString strDelPath = pItem->text();
    foreach(FileInfo* pFileInfo, m_pFileInfoList){
        if(pFileInfo->caName == strDelPath && pFileInfo->FileType != 0){
            QMessageBox::warning(this,"删除文件夹","选择的不是文件夹");
            return;
        }
    }
    //提醒用户是否确认删除
    int ret = QMessageBox::question(this, "删除文件夹", QString("是否确认删除文件夹 %1").arg(strDelPath));
    if(ret != QMessageBox::Yes){
        return;
    }
    //构建pdu并发送
    QString strPath = QString("%1/%2").arg(m_strCurPath).arg(strDelPath);
    PDU* pdu = mkPDU(strPath.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_DEL_DIR_REQUEST;
    memcpy(pdu->caMsg, strPath.toStdString().c_str(), strPath.size());
    Client::getInstance().sendPDU(pdu);
}

void File::on_rename_PB_clicked()//重命名按钮的点击
{
    //用户是否选择了文件
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    if(pItem == NULL){
        QMessageBox::warning(this,"重命名文件","请选择要重命名文件");
        return;
    }
    QString oldFileName = pItem->text();// 获取选中文件的原文件名
    QString newFileName = QInputDialog::getText(this,"重命名文件","新文件名");// 弹出对话框，获取新的文件名
    if(newFileName.isEmpty() || newFileName.size() > 32){//当前路径,判断新文件名是否为空或者长度超过32个字符
        QMessageBox::warning(this,"重命名文件","新文件名长度非法");
        return;
    }
    PDU* pdu = mkPDU(m_strCurPath.size()+1);// 创建一个PDU对象
    pdu->uiMsgType = ENUM_MSG_TYPE_RENAME_FILE_REQUEST;//设置消息类型
    memcpy(pdu->caData,oldFileName.toStdString().c_str(),32);// 将原文件名拷贝到PDU的数据区
    memcpy(pdu->caData+32,newFileName.toStdString().c_str(),32);// 将新文件名拷贝到PDU的数据区
    memcpy(pdu->caMsg, m_strCurPath.toStdString().c_str(), m_strCurPath.size());// 将当前路径拷贝到PDU的消息区
    Client::getInstance().sendPDU(pdu);// 发送PDU
}

void File::on_delFile_PB_clicked()//删除文件槽函数
{
    //用户是否选择了文件
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    if(pItem == NULL){
        QMessageBox::warning(this,"删除文件","请选择要删除的文件");
        return;
    }
    //确认用户选择的文件类型是否为文件
    QString strDelPath = pItem->text();// 获取要删除的文件路径
    foreach(FileInfo* pFileInfo, m_pFileInfoList){
        if(pFileInfo->caName == strDelPath && pFileInfo->FileType != 0){
            QMessageBox::warning(this,"删除文件","选择的不是文件");
            return;
        }
    }
    //提醒用户是否确认删除
    int ret = QMessageBox::question(this, "删除文件", QString("是否确认删除文件 %1").arg(strDelPath));
    if(ret != QMessageBox::Yes){
        return;
    }
    //构建pdu并发送
    QString strPath = QString("%1/%2").arg(m_strCurPath).arg(strDelPath);
    PDU* pdu = mkPDU(strPath.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_DEL_FILE_REQUEST;
    memcpy(pdu->caMsg, strPath.toStdString().c_str(), strPath.size());
    Client::getInstance().sendPDU(pdu);
}

void File::on_file_LW_itemDoubleClicked(QListWidgetItem *item)
{
    //获取选中的文件名
    QString strDirName = item->text();
    //判断选中的文件是否为目录
    foreach(FileInfo* pFileInfo, m_pFileInfoList){
        if(pFileInfo->caName == strDirName && pFileInfo->FileType != 0){
            QMessageBox::warning(this,"提示","选中的不是文件夹");
            return;
        }
    }
    //更新当前路径
    m_strCurPath = QString("%1/%2").arg(m_strCurPath).arg(strDirName);
    //刷新文件
    flushFile();
}

void File::on_retrun_PB_clicked()//返回上一级槽函数
{
    if(m_strCurPath == m_strUserPath){
        QMessageBox::warning(this,"返回","返回失败：已在顶层目录");
        return;
    }
    //找当前路径的最后一个斜杠
    int index = m_strCurPath.lastIndexOf('/');
    //移除包括/之后的所有字符
    m_strCurPath.remove(index,m_strCurPath.size()-index);
    //刷新文件
    flushFile();
}

void File::on_mvFile_PB_clicked()
{
    //5.按钮上文字为移动文件的操作
    if(ui->mvFile_PB->text() == "移动文件"){
        //1.获取要移动的文件
        QListWidgetItem* pItem = ui->file_LW->currentItem();
        if(pItem == NULL){
            QMessageBox::warning(this,"移动文件","请选择要移动的文件");
            return;
        }
        //2.提示选择要移动到的目录
        QMessageBox::information(this,"移动文件","请选择要移动的目录");
        //3.要移动的文件名和路径作为成员变量存下来
        m_strMoveFileName = pItem->text();
        m_strMovePath = QString("%1/%2").arg(m_strCurPath).arg(m_strMoveFileName);
        //4.按钮文字改为确认或取消
        ui->mvFile_PB->setText("确认/取消");
        return;
    }
    //6.按钮上文字为确认/取消的操作
    //判断用户是否选中目录
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    QString tarPath;
    QString boxMsg;
    if(pItem == NULL){
        //没有选择目录，移动到当前路径下
        tarPath = QString("%1/%2").arg(m_strCurPath).arg(m_strMoveFileName);//当前路径
        boxMsg = "是否移动到当前路径下";
    }else{
        //选择了目录移动到选中的目录下，判断选中的文件是否为目录
        foreach(FileInfo* pFileInfo, m_pFileInfoList){
            if(pItem->text() == pFileInfo->caName && pFileInfo->FileType != 0){
                QMessageBox::warning(this,"提示","选中的不是文件夹");
                return;
            }
        }
        tarPath = QString("%1/%2/%3").arg(m_strCurPath).arg(pItem->text()).arg(m_strMoveFileName);
        boxMsg = "是否移动到选中目录下";
    }
    //弹窗提醒用户确认或取消移动
    int ret = QMessageBox::information(this,"移动文件",boxMsg,"确认","取消");
    //按钮上的文字改为移动文件
    ui->mvFile_PB->setText("移动文件");
    if(ret != 0){//取消
        return;
    }

    //确认
    int srcLen = m_strMovePath.size();//原路径长度
    int tarLen = tarPath.size();//目标路径长度
    //构建并发送pdu
    PDU* pdu = mkPDU(srcLen+tarLen+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_MOVE_FILE_REQUEST;
    //路径的长度放入caData
    memcpy(pdu->caData,&srcLen,sizeof(int));
    memcpy(pdu->caData+32,&tarLen,sizeof(int));
    //源路径和目标路径放入caMsg
    memcpy(pdu->caMsg,m_strMovePath.toStdString().c_str(),srcLen);
    memcpy(pdu->caMsg+srcLen+1,tarPath.toStdString().c_str(),tarLen);
    //发送
    Client::getInstance().sendPDU(pdu);
}

void File::on_upload_PB_clicked()
{
    //判断是否已有文件在上传，同时只有一个文件上传
    if(m_bUpload){
        QMessageBox::warning(this,"上传文件","已有文件正在上传");
        return;
    }
    //通过文件选择弹窗获取用户选择的文件路径，路径作为File的成员变量存下来
    m_strUploadFilePath.clear();
    m_strUploadFilePath = QFileDialog::getOpenFileName();
    if(m_strUploadFilePath == ""){
        return;
    }
    qDebug()<<"m_strUploadFilePath"<<m_strUploadFilePath;

    //构建PDU，文件名和文件大小放入caData，当前路径放入caMsg
    PDU* pdu = mkPDU(m_strCurPath.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_REQUEST;
    //获取文件名
    int index = m_strUploadFilePath.lastIndexOf('/');
    QString strFileName = m_strUploadFilePath.right(m_strUploadFilePath.size()-index-1);
    //获取文件大小
    QFile file(m_strUploadFilePath);
    qint64 iFileSize = file.size();

    memcpy(pdu->caData,strFileName.toStdString().c_str(),32);
    memcpy(pdu->caData+32, &iFileSize, sizeof(qint64));
    memcpy(pdu->caMsg,m_strCurPath.toStdString().c_str(),m_strCurPath.size());
    //发送
    Client::getInstance().sendPDU(pdu);
}

void File::on_download_PB_clicked()//下载文件槽函数
{
    //判断是否已有文件在下载
    if(m_bDownload){
        QMessageBox::warning(this,"下载文件","已有文件正在下载");
        return;
    }
    //是否已选择下载文件
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    if(pItem == NULL){
        QMessageBox::warning(this,"下载文件","请选择要下载的文件");
        return;
    }

    //通过文件选择弹窗获取用户选择的文件保存路径
    m_strSavePath = QFileDialog::getSaveFileName();
    qDebug() << "m_strSavePath" << m_strSavePath;
    if(m_strSavePath == ""){
        return;
    }

    //拼接下载的文件完整路径，发送给服务器
    m_strDownloadFileName = pItem->text();
    QString strPath = m_strCurPath + "/" + m_strDownloadFileName;

    PDU* pdu = mkPDU(strPath.size()+1);
    pdu->uiMsgType = ENUM_MSG_TYPE_DOWNLOAD_FILE_REQUEST;
    memcpy(pdu->caMsg,strPath.toStdString().c_str(),strPath.size());
    Client::getInstance().sendPDU(pdu);
}

void File::on_shareFile_PB_clicked()//分享文件槽函数
{
    QListWidgetItem* pItem = ui->file_LW->currentItem();
    if(pItem == NULL){
        QMessageBox::warning(this,"分享文件","请选择要分享的文件");
        return;
    }
    m_strShareFileName = pItem->text();
    m_pShareFile->updateFriend_LW();
    if(m_pShareFile->isHidden()){
        m_pShareFile->show();
    }

}
